<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      // 浅谈闭包和回调函数
      /*闭包是一个非常重要的概念，它允许函数记住并访问其所在的作用域，
      即使该函数在其作用域之外执行。闭包通常由一个外部函数和一个或多个内部函数组成，
      内部函数可以在访问外部函数的变量（内部函数在其它作用域执行时，非当前外部函数作用域）。
      以下是一个使用闭包的示例 */
      function outerFunction(outerVariable) {
        // 这是一个内部函数，它可以访问外部函数outerFunction的变量
        function innerFunction() {
          console.log("内部函数访问了外部函数的变量:", outerVariable);
        }
        // 返回内部函数，这样我们就可以在外部环境中调用它
        return innerFunction;
      }
      // 调用外部函数，并将返回的内部函数赋值给一个变量
      var closedOverFunction = outerFunction("这是一个外部变量");
      // 现在我们可以调用closedOverFunction，尽管它是在outerFunction的作用域之外调用的
      // 但它仍然可以访问到outerVariable，实现了在其它作用域访问到了outerFunction的作用域内部的变量
      closedOverFunction(); // 输出: 内部函数访问了外部函数的变量: 这是一个外部变量
      /* 在这个例子中，outerFunction 是一个外部函数，它接受一个参数 outerVariable。outerFunction 
      内部定义了一个名为 innerFunction 的内部函数，
      该函数可以访问 outerVariable。然后，outerFunction 返回 innerFunction 的引用。
      当我们调用 outerFunction 并将其返回值（即 innerFunction 的引用）存储在 closedOverFunction 变量中时，
      就创建了一个闭包。此时，尽管 outerFunction 已经执行完毕，但其内部变量 outerVariable 
      仍然被 innerFunction（现在被引用为 closedOverFunction）所记住和访问。这就是闭包的作用。 */
      function greetAfterTimeout(name, callback) {
        return () => {
          console.log(`Hello, ${name}!`); //一个箭头函数内部访问到了外部函数作用域name这个变量
          callback(name); //调用回调函数访问到了外部函数作用域name这个变量
          setTimeout(function (val) {
            //注意这个函数不能接受参数，因为接受了参数以后也是无效的，这个回调函数在setTimeout函数内部执行的时并没有传入参数，
            //cb:回调函数是否可以接受参数，要看在外部函数内部执行回调函数时是否传入了参数，ps:但只要传入了参数就访问了外部函数的变量，即形成了闭包
            //cb:上面那个callback回调函数就是传入了参数，形成了闭包
            console.log(val); //输出undefined，不管参数变量名是什么，都是undefined(包括name)
            console.log(name); //箭头函数内部定时器的回调函数也可以访问到外部作用域的name(如果没有参数名!=name)
          }, 2000);
        };
      }

      function sayGoodbye(val) {
        console.log(`${val},Goodbye!`);
      }
      const kkx = greetAfterTimeout("Alice", sayGoodbye); // 先打印 "Hello, Alice!"，"Alice,Goodbye!"，两秒后打印 'undefined',"Alice"
      kkx();
      // 1.闭包就是希望获取到其它函数内部的数据，所以把自己写到其它函数内部，调用该函数内部的数据
      // 如果希望在其他作用域（全局，另外的函数作用域）也可以用，就return出来，不管处在任何作用域下，都能访问该函数（之前写到这个函数内部）内部的数据;高级函数的一种：return出来一个函数
      // 2.回调函数是把一个函数当做参数传入外部函数内部，此时这个函数内部可以使用外部函数的变量，该回调函数使用变量就形成了闭包（这个函数可以访问外部函数变量了）
      // 而且这个函数还可以传入参数，接收的参数就是外部函数作用域的变量，实现了回调函数使用外部函数的变量（非外部函数自定义的变量）;高级函数的另一种：一个函数作为参数，常说的回调函数
    </script>
  </body>
</html>
